package com.atomos.particle
{
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import com.atomos.strategy.emission.MockAtStartEmission;
	import com.atomos.system.AbstractParticleSystem;
	import com.atomos.system.MockParticleSystem;
	import com.atomos.system.ParticleSystem;
	import com.atomos.utils.PointUtils;
	import com.bourre.collection.Iterator;
	import com.bourre.collection.WeakCollection;
	
	import flexunit.framework.TestCase;		

	public class ParticleManagerTest extends TestCase
	{
		private var _manager : ParticleManager;
		
		public override function setUp():void
		{
			_manager = ParticleManager.getInstance();
		}
		
		public override function tearDown () : void
		{
			ParticleManager.release();
			_manager = null;
		}
		
		public function testConstruct () : void
		{
			assertNotNull ( "ParticleManager.getInstance() failed to return a valid instance", _manager ); 
		}
		
		public function testAddRemoveParticleSystem () : void
		{
			assertEquals ( _manager + " has particle system before adding the first particle system", 
						   0, _manager.getParticleSystemsCount() );
			
			var e1 : ParticleSystem = new MockParticleSystem();
			
			_manager.addParticleSystem( e1 );
			
			var c : WeakCollection = _manager.getParticleSystems();
			var e : ParticleSystem = c.iterator().next() as ParticleSystem;
			
			assertEquals ( _manager + ".getParticleSystemsCount() don't return the right value after adding a particle system",
						   1, _manager.getParticleSystemsCount() );
			assertTrue ( "Collection returned by "+ _manager + ".getParticleSystems() don't contains the previously added particle system", 
						 c.contains( e1 ) );
			assertEquals ( "ParticleSystem contained in "+ _manager + " isn't the particle system added", e1, e );	
			
			_manager.addParticleSystem( e1 );
			
			assertEquals ( _manager + ".addParticleSystem() don't failed to not add the last inserted element in the set", 1, _manager.getParticleSystemsCount() );
			
			
			var e2 : ParticleSystem = new MockParticleSystem();
			var e3 : ParticleSystem = new MockParticleSystem();
			_manager.addParticleSystem( e2 );
			_manager.addParticleSystem( e3 );
			
			assertEquals ( _manager + ".getParticleSystemsCount() don't return the right value after adding 2 more particle systems",
						   3, _manager.getParticleSystemsCount() );
			
			_manager.removeParticleSystem( e1 );
			
			assertEquals ( _manager + ".getParticleSystemsCount() don't return the right value after remove a particle systems",
						   2, _manager.getParticleSystemsCount() );
			
			_manager.removeParticleSystem( e2 );
			_manager.removeParticleSystem( e3 );
			
			assertEquals ( _manager + ".getParticleSystemsCount() don't return the right value after remove all particle systems",
						   0, _manager.getParticleSystemsCount() );
			
		}
				
		public function testAddRemoveParticle () : void
		{
			assertEquals ( _manager + " has particle before adding the first particle", 
						   0, _manager.getParticlesCount() );
			
			var p1 : Particle = new Particle();
			
			_manager.addParticle( p1 );
			
			var c : WeakCollection = _manager.getParticles();
			var p : Particle = c.iterator().next() as Particle;
			
			assertNotNull ( _manager + ".getParticles() return a null collection", c );
			assertEquals ( _manager + ".getParticlesCount() don't return the right value after adding an particle",
						   1, _manager.getParticlesCount() );
			assertTrue ( "Collection returned by "+ _manager + ".getParticles() don't contains the previously added particle", 
						 c.contains( p1 ) );
			assertEquals ( "Particle contained in "+ _manager + " isn't the particle added", p1, p );
			
			var p2 : Particle = new Particle();
			var p3 : Particle = new Particle();
			_manager.addParticle( p2 );
			_manager.addParticle( p3 );
			
			assertEquals ( _manager + ".getParticlesCount() don't return the right value after adding 2 more particles",
						   3, _manager.getParticlesCount() );
			
			_manager.removeParticle( p1 );
			
			assertEquals ( _manager + ".getParticlesCount() don't return the right value after remove a particles",
						   2, _manager.getParticlesCount() );
			
			_manager.removeParticle( p2 );
			_manager.removeParticle( p3 );
			
			assertEquals ( _manager + ".getParticlesCount() don't return the right value after remove of all particles",
						   0, _manager.getParticlesCount() );
		}
				
		public function testGetParticlesByType () : void
		{
			var p1 : Particle = new MockParticle();
			var p2 : Particle = new MockParticle();
			var p3 : Particle = new MockParticle();
			var p4 : Particle = new MockAnotherParticle();
			var p5 : Particle = new MockAnotherParticle();
			var p6 : Particle = new MockAnotherParticle();
			
			_manager.addParticle( p1 );
			_manager.addParticle( p2 );
			_manager.addParticle( p3 );
			_manager.addParticle( p4 );
			_manager.addParticle( p5 );
			_manager.addParticle( p6 );
			
			var c1 : WeakCollection = _manager.getParticlesByType( MockParticle );		
			var c2 : WeakCollection = _manager.getParticlesByType( MockAnotherParticle );
			var i1 : Iterator = c1.iterator();
			var i2 : Iterator = c2.iterator();
			var n1 : Number = 0;
			var n2 : Number = 0;
			var p : *;
			
			
			assertNotNull ( _manager + ".getParticlesByType return a null collection", c1 );
			assertEquals( c1 + " returned by " + _manager + " don't match the correct size", 3, c1.size() );
			while( i1.hasNext() )
			{
				p = i1.next();
				
				assertNotNull ( "Particle " + p + " contained in " + c1 + " can't be casted as MockParticle at " + n1,
								 p as MockParticle );
				
				n1++;
			}
			
			assertNotNull ( _manager + ".getParticlesByType return a null collection", c2 );
			assertEquals( c2 + " returned by " + _manager + " don't match the correct size", 3, c2.size() );
			while( i2.hasNext() )
			{
				p = i2.next();
				
				assertNotNull ( "Particle " + p +  " contained in " + c2 + " can't be casted as MockAnotherParticle at " + n2,	
								p as MockAnotherParticle );
				
				n2++;
			}
		}

		public function testGetParticlesByParticleSystem () : void
		{
			var e : ParticleSystem = new AbstractParticleSystem();
			e.emit( new MockAtStartEmission ( Particle ) );
			
			assertNotNull ( _manager + ".getParticlesByParticleSystem() return a null collection", _manager.getParticlesByParticleSystem( e ) );
			assertEquals ( "Collection returned by "+_manager+" is not the same than the particle system one", 
						   e.getParticles(), _manager.getParticlesByParticleSystem( e ) );
		}
		
		public function testGetParticlesByArea () : void
		{
			var numParticles : Number = 16;
			var x : Number = 0;
			var y : Number = 0;
			var p : Particle;
			
			while( numParticles-- )
			{
				p = new Particle();
				p.position.x = x;
				p.position.y = y;
				_manager.addParticle( p );
				
				x++;
				if( x >= 4 ) { x = 0, y++; }
			}
			
			var c : WeakCollection = _manager.getParticlesByArea( new Rectangle ( 0, 0, 2, 2 ) );
			
			assertNotNull ( _manager + ".getParticlesByArea() return a null collection", c );
			assertEquals ( _manager + ".getParticlesByArea() don't return the correct number of particles", 9, c.size() );
			var i : Iterator = c.iterator();
			
			while( i.hasNext() )
			{
				p = i.next() as Particle;
				var xIn : Boolean = p.position.x <= 2 && p.position.x >= 0;
				var yIn : Boolean = p.position.y <= 2 && p.position.y >= 0;
				
				assertTrue ( "Particles " + p + " returned by the manager isn't in the area", xIn && yIn );
			}
		}
		
		public function testGetParticlesByDistanceFrom () : void
		{
			var numParticles : Number = 16;
			var x : Number = 0;
			var y : Number = 0;
			var p : Particle;
			
			while( numParticles-- )
			{
				p = new Particle();
				p.position.x = x;
				p.position.y = y;
				_manager.addParticle( p );
				
				x++;
				if( x >= 4 ) { x = 0, y++; }
			}
			
			var c : WeakCollection = _manager.getParticlesByDistanceFrom( new Point( 1, 1 ), 1 );
			
			assertNotNull ( _manager + ".getParticlesByDistanceFrom() return a null collection", c );
			assertEquals ( _manager + ".getgetParticlesByDistanceFrom() don't return the correct number of particles", 5, c.size() );
			var i : Iterator = c.iterator();
			
			while( i.hasNext() )
			{
				p = i.next() as Particle;
				var dist : Number = PointUtils.distance( new Point ( 1, 1 ), p.position );
				
				assertTrue ( "Particles " + p + " returned by the manager isn't in the area", dist <= 1 );
			}
		}
		
		public function testStartStopAllParticleSystems () : void
		{
			var e1 : ParticleSystem = new AbstractParticleSystem();
			var e2 : ParticleSystem = new AbstractParticleSystem();
			
			_manager.startAllParticleSystems();
			
			assertTrue( _manager + ".startAllParticleSystems() haven't start particle systems", e1.isRunning() && e2.isRunning() );
			
			_manager.stopAllParticleSystems();
			
			assertFalse( _manager + ".stopAllParticleSystems() haven't stop particle systems", e1.isRunning() || e2.isRunning() );
		}
		
		public function testClear () : void
		{
			var e1 : ParticleSystem = new AbstractParticleSystem();
			var e2 : ParticleSystem = new AbstractParticleSystem();
			
			var p1 : Particle = new MockParticle();
			var p2 : Particle = new MockParticle();
			var p3 : Particle = new MockParticle();
			var p4 : Particle = new MockAnotherParticle();
			var p5 : Particle = new MockAnotherParticle();
			var p6 : Particle = new MockAnotherParticle();
			
			_manager.addParticle( p1 );
			_manager.addParticle( p2 );
			_manager.addParticle( p3 );
			_manager.addParticle( p4 );
			_manager.addParticle( p5 );
			_manager.addParticle( p6 );
			
			assertTrue ( _manager + ".getParticlesCount() before clear() don't return 6", 6, _manager.getParticlesCount() );
			assertTrue ( _manager + ".getParticleSystemsCount() before clear() don't return 2", 2, _manager.getParticleSystemsCount() );
			
			_manager.clear();
			
			assertTrue ( _manager + ".getParticlesCount() after clear() don't return 0", 0, _manager.getParticlesCount() );
			assertTrue ( _manager + ".getParticleSystemsCount() after clear() don't return 0", 0, _manager.getParticleSystemsCount() );
		}
	}
}